package com.mg.plugin.cropgrow.calculator;

import com.mg.plugin.cropgrow.entity.CropGrowData;
import com.mg.plugin.cropgrow.entity.CropGrowProData;
import com.mg.plugin.cropgrow.entity.StationData;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class CropGrowProCalculator {

    public static List<CropGrowProData> calcCropGrowPro(List<StationData> stationDataList, PlantType plantType) throws ParseException {
        List<CropGrowProData> result = new ArrayList<CropGrowProData>();
        SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
        List<CropGrowData> cropGrowData = CropGrowCalculator.calcCropGrow(stationDataList, plantType);
        for (CropGrowData data : cropGrowData) {
            List<StationData> stationDatas = data.getStationDataList();
            double totalEt = 0;
            Date beginDate = sdfDate.parse(data.getPlantDay());
            double jmEt = data.getLeafFU();
            double accTem10 = 0;
            double qa = 0;
            double bAccTemp = 0.6 * data.getCropLeafCount() + 11.6;
            double leafAge = 0;
            //插播叶龄
            double g = calcLeafAge6(data.getRiceTrans());
            //分蘖高峰期
            double fbMax = 1.42875 * (3.41 * data.getCropLeafCount() - 23.6);
            //分蘖累积积温
            double fbT = 0;
            int endLeafIndex = calcObsGhoDay(stationDatas, sdfDate, sdfTime, data);
            System.out.println("LeafIndex:" + endLeafIndex);

            for (StationData stationData : stationDatas) {
                Date calcDate = sdfTime.parse(stationData.getDate());
                CropGrowProData cropGrowProData = new CropGrowProData(data);
                cropGrowProData.setDate(sdfDate.format(calcDate));
                if (beginDate.before(calcDate)) {
                    double filmTempDiff = 0;
                    double filmEtDiff = 0;
                    if (jmEt > totalEt) {
                        filmTempDiff = calcFilmTempDiff(stationData.getSunshine());
                        totalEt += calcET(stationData.getAvgTemp() + filmTempDiff);
                        filmEtDiff = calcET(stationData.getAvgTemp() + filmTempDiff) - stationData.getEffectTemp();
                    } else {
                        totalEt += stationData.getEffectTemp();
                    }
                    if (leafAge <= 4.8) {
                        leafAge = calcLeafAge6(totalEt);
                        qa = totalEt;
                    } else if (leafAge < g + 1.5 && plantType == PlantType.A) {
                        leafAge = calcLeafAge37(totalEt, qa, g);
                    } else {
                        leafAge = calcLeafAge66(totalEt, g);
                    }

//                    leafAge = calcLeafAge6(totalEt);
                    if (leafAge > data.getCropLeafCount()) {
                        leafAge = data.getCropLeafCount();
                    }

                    double groutEt = 0;
                    if (totalEt >= data.getEarStage() && stationData.getAvgTemp() >= 10) {
                        //灌浆累积？？？？？？？？？？？
                        groutEt = stationData.getAvgTemp() - 10;
                        accTem10 += groutEt;
                    }

                    stationData.setTotalEt(totalEt);

                    leafAge = leafAge < 0 ? 0 : leafAge;
                    //当量积温，已确定
                    cropGrowProData.setEt(calcET(stationData.getAvgTemp() + filmTempDiff));
                    //叶龄，直播待确定
                    cropGrowProData.setLeafAge(leafAge);
                    //膜温度差，已确定
                    cropGrowProData.setFilmTempDiff(filmTempDiff);
                    //膜当量差，已确定
                    cropGrowProData.setFilmEtDiff(filmEtDiff);
                    //分蘖当量，已确定
                    cropGrowProData.setTillerEt(calcTillerEt(stationData, data.getCropLeafCount(), leafAge));
                    fbT += cropGrowProData.getTillerEt();
                    //分蘖进程,已确定
                    cropGrowProData.setTillerPro(calcTillerPro(fbMax, fbT, data.getCropLeafCount(), leafAge));
                    //空壳率,已确定
                    cropGrowProData.setObsGho(calcObsGho(data, stationData, bAccTemp, endLeafIndex, stationDatas.indexOf(stationData)));
                    //灌浆当量，已确定
                    double get = calcGroutHot(accTem10, data.getGroutLength());
                    cropGrowProData.setGroutEt(get);
                    //灌浆进程，已确定
                    cropGrowProData.setGroutPro(accTem10 > 0 ? calcGroutPro(get) : 0);
                }
                result.add(cropGrowProData);
            }
        }

        return result;
    }

    private static int calcObsGhoDay(List<StationData> stationDatas, SimpleDateFormat sdfDate, SimpleDateFormat sdfTime, CropGrowData data) throws ParseException {
        Date beginDate = sdfDate.parse(data.getPlantDay());
        double jmEt = data.getLeafFU();
        double totalEt = 0;
        int endLeafIndex = -1;
        for (StationData stationData : stationDatas) {
            Date calcDate = sdfTime.parse(stationData.getDate());
            CropGrowProData cropGrowProData = new CropGrowProData(data);
            cropGrowProData.setDate(sdfDate.format(calcDate));
            if (beginDate.before(calcDate)) {
                if (jmEt > totalEt) {
                    double filmTempDiff = calcFilmTempDiff(stationData.getSunshine());
                    totalEt += calcET(stationData.getAvgTemp() + filmTempDiff);
                } else {
                    totalEt += stationData.getEffectTemp();
                }
                if (totalEt >= data.getEndLeaf() && endLeafIndex < 0) {
                    endLeafIndex = stationDatas.indexOf(stationData);
                }
            }
        }
        return endLeafIndex;
    }

    public static double calcGroutHot(double groutEt, double cropLeafCount) {
        return groutEt / cropLeafCount * 100;
    }

    //公式9
    private static double calcFilmTempDiff(double sunshine) {
        return 4.2 / (1 + Math.pow(Math.E, -9.19024 * (sunshine - 5.3) / 13.8)) + 1.4;
    }

    //公式16
    public static double calcLeafAge66(double totalEt, double g) {
        double d0 = (0.456 * g - 14.46) * g + 60.91;
        return (Math.sqrt(16.456 * 16.456 - 10.104 * (77.31 - d0 + 30 - totalEt)) - 16.456) / 5.052;
    }

    //公式13
    public static double calcLeafAge37(double et, double qa, double g) {
        double ws = 7.587 * g + 30.4 + 30;
        return 1.5 * Math.pow((et - qa) / ws, 2) + g;
    }

    //公式7
    public static double calcLeafAge6(double totalEt) {
        return (Math.sqrt(30.91 * 30.91 - 8.28 * (16.4 - totalEt)) - 30.91) / 4.14;
    }

    //公式39
    public static double calcGroutPro(double v) {
        //TODO参数有调整
        double res = 148.836 / (1 + Math.pow(Math.E, -9.19024 * (v - 56) / 202)) - 34.697;
        return res > 0 ? res : 0;
    }

    private static double calcObsGho(CropGrowData data, StationData stationData, double bAccTemp, int endLeafIndex, int stationIndex) {
        int i = stationIndex + 8 - endLeafIndex;
        double obsGho = CropGrowDateCalculator.calcObsGho(stationData.getTotalEt(), data, stationData, bAccTemp);
        double obsGhoRatio = CropGrowDateCalculator.calcObsGhoRatio(i);
        double res = obsGho * obsGhoRatio;
        if (res > 10) {
            System.out.println("TMAX:" + stationData.getMaxTemp() + "TMIN:" + stationData.getMinTemp() + "bAccTemp:" + bAccTemp + "obsGhoRatio:" + obsGhoRatio);
        }
        return res < 0 ? 0 : res;
    }

    //分蘖当量计算，已确定
    public static double calcTillerEt(StationData stationData, double cropLeafCount, double leafAge) {
        if (leafAge < 0.33 * cropLeafCount || leafAge > 2.0 * (3.41 * cropLeafCount - 23.6)) {
            return 0;
        }
        return 1.014 / (1 + Math.pow(Math.E, (-9.19024 * (stationData.getAvgTemp() - 15.5) / 16.7))) - 0.012;
    }

    private static double calcTillerPro(double fbMax, double fbt, double cropLeafCount, double leafAge) {
        if (leafAge < 0.33 * cropLeafCount || leafAge > 2.0 * (3.41 * cropLeafCount - 23.6)) {
            return 0;
        }
        double fnEt = fbt / fbMax * 100;
        if (fnEt <= 100) {
            fnEt = (fnEt - 59) / 100;
            return 102.22 / (1 + Math.pow(Math.E, -9.19024 * fnEt));
        }
        fnEt = (120 - fnEt) / 40;
        return 1.0101 * 25 / (1 + Math.pow(Math.E, -9.19024 * fnEt)) + 75;
    }

    /**
     * 当量温度计算公式
     *
     * @param temp
     * @return
     */
    private static double calcET(double temp) {
        double power = 9.19024 * Math.pow((temp - 26.1) / 26.7, 2) - 4.59512 * 0.22;
        return 15.603 / (1 + Math.pow(Math.E, power));
    }

}
